package com.molyfun.parents.view.RecordView;

import android.content.Context;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Handler;
import android.os.Message;
import android.text.format.Time;
import android.util.Log;

import com.molyfun.parents.MFPApplication;
import com.molyfun.parents.activity.record.mp3recoder.DataEncodeThread;
import com.molyfun.parents.activity.record.mp3recoder.Mp3Recorder;
import com.molyfun.parents.activity.record.mp3recoder.PCMFormat;
import com.molyfun.parents.activity.record.mp3recoder.RingBuffer;
import com.molyfun.parents.activity.record.mp3recoder.SimpleLame;
import com.molyfun.parents.utils.FileUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;

/**
 * Created by william(liuchao.hit@gmail.com).
 * Date:10/18/16.
 */
public class VoiceRecorder {

    private static final String TAG = Mp3Recorder.class.getSimpleName();

    static {
        System.loadLibrary("mp3lame");
    }
    private static final int DEFAULT_SAMPLING_RATE = 22050;

    private static final int FRAME_COUNT = 160;

    /* Encoded bit rate. MP3 file will be encoded with bit rate 32kbps */
    private static final int BIT_RATE = 32;

    private AudioRecord audioRecord = null;

    private int bufferSize;

    private File mp3File;

    private RingBuffer ringBuffer;

    private byte[] buffer;

    private FileOutputStream os = null;

    private DataEncodeThread encodeThread;

    private int samplingRate;

    private int channelConfig;

    private PCMFormat audioFormat;

    static final String PREFIX = "voice";
    static final String EXTENSION = ".mp3";

    private boolean isRecording = false;
    private long startTime;
    private String voiceFilePath = null;
    private String voiceFileName = null;
    private Handler handler;

    public VoiceRecorder(Handler handler) {
        this.handler = handler;
        this.samplingRate = DEFAULT_SAMPLING_RATE;
        this.channelConfig = AudioFormat.CHANNEL_IN_MONO;
        this.audioFormat = PCMFormat.PCM_16BIT;
    }

    /**
     * start recording to the file
     */
    public void startRecording(Context appContext) throws IOException {

        if (isRecording) return;
        Log.d(TAG, "Start recording");
        Log.d(TAG, "BufferSize = " + bufferSize);
        // Initialize audioRecord if it's null.
        if (audioRecord == null) {
            initAudioRecorder();
        }
        audioRecord.startRecording();
        startTime = new Date().getTime();
        new Thread() {

            @Override
            public void run() {
                isRecording = true;
                while (isRecording && (audioRecord != null)) {
                    int bytes = audioRecord.read(buffer, 0, bufferSize);
                    if (bytes > 0) {
                        ringBuffer.write(buffer, bytes);
                    }
                }

                // release and finalize audioRecord
                try {
                    if(audioRecord != null){
                        audioRecord.stop();
                        audioRecord.release();
                        audioRecord = null;
                    }

                    // stop the encoding thread and try to wait
                    // until the thread finishes its job
                    Message msg = Message.obtain(encodeThread.getHandler(),
                            DataEncodeThread.PROCESS_STOP);
                    msg.sendToTarget();

                    Log.d(TAG, "waiting for encoding thread");
                    encodeThread.join();
                    Log.d(TAG, "done encoding thread");
                } catch (InterruptedException e) {
                    Log.d(TAG, "Faile to join encode thread");
                } catch (IllegalStateException e) {
                    Log.d(TAG, "IllegalStateException");
                } finally {
                    if (os != null) {
                        try {
                            os.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }

            }
        }.start();




//        new Thread(new Runnable() {
//            @Override
//            public void run() {
//                try {
//                    while (isRecording) {
//                        android.os.Message msg = new android.os.Message();
//                        msg.what = recorder.getMaxAmplitude() * 5 / 0x7FFF;
//                        handler.sendMessage(msg);
//                        SystemClock.sleep(100);
//                    }
//                } catch (Exception e) {
//                    // from the crash report website, found one NPE crash from
//                    // one android 4.0.4 htc phone
//                    // maybe handler is null for some reason
//                    Log.e("voice", e.toString());
//                }
//            }
//        }).start();
//
//        Log.d("voice", "start voice recording to file:" + file.getAbsolutePath());
//        return file == null ? null : file.getAbsolutePath();
    }


    /**
     * Initialize audio recorder
     */
    private void initAudioRecorder() throws IOException {
        int bytesPerFrame = audioFormat.getBytesPerFrame();
		/* Get number of samples. Calculate the buffer size (round up to the
		   factor of given frame size) */
        int frameSize = AudioRecord.getMinBufferSize(samplingRate,
                channelConfig, audioFormat.getAudioFormat()) / bytesPerFrame;
        if (frameSize % FRAME_COUNT != 0) {
            frameSize = frameSize + (FRAME_COUNT - frameSize % FRAME_COUNT);
            Log.d(TAG, "Frame size: " + frameSize);
        }

        bufferSize = frameSize * bytesPerFrame;

		/* Setup audio recorder */
        audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
                samplingRate, channelConfig, audioFormat.getAudioFormat(),
                bufferSize);

        // Setup RingBuffer. Currently is 10 times size of hardware buffer
        // Initialize buffer to hold data
        ringBuffer = new RingBuffer(10 * bufferSize);
        buffer = new byte[bufferSize];

        // Initialize lame buffer
        // mp3 sampling rate is the same as the recorded pcm sampling rate
        // The bit rate is 32kbps
        SimpleLame.init(samplingRate, 1, samplingRate, BIT_RATE);

        voiceFileName = getVoiceFileName(MFPApplication.getInstance().getUser().getId());
        voiceFilePath = FileUtils.VOICEPATH + "/" + voiceFileName ;//+ EXTENSION;
        mp3File = new File(voiceFilePath);
        os = new FileOutputStream(mp3File);

        // Create and run thread used to encode data
        // The thread will
        encodeThread = new DataEncodeThread(ringBuffer, os, bufferSize);
        encodeThread.start();
        audioRecord.setRecordPositionUpdateListener(encodeThread, encodeThread.getHandler());
        audioRecord.setPositionNotificationPeriod(FRAME_COUNT);
    }

    /**
     * stop the recoding
     *
     * @return seconds of the voice recorded
     */

    public void discardRecording() {
        if (audioRecord != null) {
            try {
//                audioRecord.stop();
//                audioRecord.release();
//                audioRecord = null;
                if (mp3File != null && mp3File.exists() && !mp3File.isDirectory()) {
                    mp3File.delete();
                }
            } catch (IllegalStateException e) {
            } catch (RuntimeException e){}
            isRecording = false;
        }
    }

    public int stopRecoding() {
        isRecording = false;
        int seconds = (int) (new Date().getTime() - startTime) / 1000;
//        Log.d("voice", "voice recording finished. seconds:" + seconds + " file length:" + file.length());
        return seconds;
//        if(audioRecord != null){
//            isRecording = false;
//            audioRecord.stop();
//            audioRecord.release();
//            audioRecord = null;
//
//            if(file == null || !file.exists() || !file.isFile()){
//                return ErrorCode.FILE_INVALID;
//            }
//            if (file.length() == 0) {
//                file.delete();
//                return ErrorCode.FILE_INVALID;
//            }
//            int seconds = (int) (new Date().getTime() - startTime) / 1000;
//            Log.d("voice", "voice recording finished. seconds:" + seconds + " file length:" + file.length());
//            return seconds;
//        }
//        return 0;
    }

    protected void finalize() throws Throwable {
        super.finalize();
        if (audioRecord != null) {
            audioRecord.release();
        }
    }

    private String getVoiceFileName(String uid) {
        Time now = new Time();
        now.setToNow();
        return uid + now.toString().substring(0, 15) + EXTENSION;
    }

    public boolean isRecording() {
        return isRecording;
    }


    public String getVoiceFilePath() {
        return voiceFilePath;
    }

    public String getVoiceFileName() {
        return voiceFileName;
    }
}
